# 导入neo4j官方驱动包
from neo4j import GraphDatabase

# 设置Neo4j数据库的连接地址
uri = "bolt://localhost:7687"
# 设置认证信息（用户名和密码）
auth = ("neo4j", "12345678")
# 创建数据库驱动对象
driver = GraphDatabase.driver(uri, auth=auth)


# 初始化数据库，创建测试用户和图书
def initialize_db():
    """初始化数据库，创建测试用户和图书"""
    # 定义需要依次执行的Cypher语句列表
    cyphers = [
        # 删除所有节点及其关系
        "MATCH (n) DETACH DELETE n",
        # 创建4个用户节点
        """
        CREATE 
          (u1:User {account: 'user001', name: '张三'}),
          (u2:User {account: 'user002', name: '李四'}),
          (u3:User {account: 'user003', name: '王五'}),
          (u4:User {account: 'user004', name: '赵六'})
        """,
        # 创建6本图书节点
        """
        CREATE
          (b1:Book {isbn: 'isbn1', title: 'isbn1'}),
          (b2:Book {isbn: 'isbn2', title: 'isbn2'}),
          (b3:Book {isbn: 'isbn3', title: 'isbn3'}),
          (b4:Book {isbn: 'isbn4', title: 'isbn4'}),
          (b5:Book {isbn: 'isbn5', title: 'isbn5'}),
          (b6:Book {isbn: 'isbn6', title: 'isbn6'})
        """,
        # 创建初始借阅记录（user001、user002各借isbn1、isbn2）
        """
        MATCH (u:User), (b:Book)
        WHERE u.account IN ['user001', 'user002']  AND b.isbn IN ['isbn1', 'isbn2']
        CREATE (u)-[:BORROWED {borrow_date: date()}]->(b)
        """,
    ]
    # 打开数据库会话，指定数据库为books
    with driver.session(database="books") as session:
        # 依次执行每条Cypher语句
        for cypher in cyphers:
            session.run(cypher)
    # 打印初始化完成提示
    print("数据库初始化完成！")


# 借书：为指定用户和图书创建BORROWED关系，记录借阅日期
def borrow_book(account, isbn):
    # 定义Cypher语句，查找用户和图书节点并创建借阅关系
    cypher = """
    MATCH (u:User {account: $account}), (b:Book {isbn: $isbn})
    CREATE (u)-[:BORROWED {borrow_date: date()}]->(b)
    """
    # 打开数据库会话，指定数据库为books
    with driver.session(database="books") as session:
        # 执行Cypher语句，传入参数
        session.run(cypher, account=account, isbn=isbn)


# 还书：为指定用户和图书的BORROWED关系设置归还日期
def return_book(account, isbn):
    # 定义Cypher语句，查找借阅关系并设置归还日期
    cypher = """
    MATCH (u:User {account: $account})-[r:BORROWED]->(b:Book {isbn: $isbn})
    SET r.return_date = date()
    """
    # 打开数据库会话，指定数据库为books
    with driver.session(database="books") as session:
        # 执行Cypher语句，传入参数
        session.run(cypher, account=account, isbn=isbn)


# 推荐：基于协同过滤，推荐与目标用户兴趣相似的其他用户借阅过的图书
def recommend_books(account):
    # 定义Cypher语句，查找推荐图书及推荐理由
    cypher = """
    MATCH (u1:User {account: $account})-[:BORROWED]->(b:Book)<-[:BORROWED]-(u2:User),
          (u2)-[:BORROWED]->(rec:Book)
    WHERE NOT (u1)-[:BORROWED]->(rec)
    RETURN rec.title AS 推荐书籍, count(*) AS 推荐理由
    ORDER BY 推荐理由 DESC LIMIT 5
    """
    # 打开数据库会话，指定数据库为books
    with driver.session(database="books") as session:
        # 执行Cypher语句，传入参数
        result = session.run(cypher, account=account)
        # 遍历结果，打印推荐书籍及推荐理由
        for record in result:
            print(record["推荐书籍"], record["推荐理由"])


# 显示当前借阅状态
def show_borrowing_status():
    """显示当前借阅状态"""
    # 定义Cypher语句，查找所有未归还的借阅关系
    cypher = """
    MATCH (u:User)-[r:BORROWED]->(b:Book)
    WHERE r.return_date IS NULL
    RETURN u.account AS 用户账号, u.name AS 姓名, 
           b.title AS 图书, r.borrow_date AS 借阅日期
    ORDER BY 借阅日期
    """
    # 打开数据库会话，指定数据库为books
    with driver.session(database="books") as session:
        # 执行Cypher语句
        result = session.run(cypher)
        # 打印标题
        print("\n当前借阅状态：")
        print("-" * 50)
        # 遍历结果，逐条打印借阅信息
        for record in result:
            print(
                f"{record['姓名']}({record['用户账号']}) 正在借阅《{record['图书']}》"
                f"(借于 {record['借阅日期']})"
            )


# 主程序入口
if __name__ == "__main__":
    try:
        # 1. 初始化数据库
        initialize_db()

        # 2. 借书操作
        borrow_book("user003", "isbn3")  # 王五借阅《isbn3》
        borrow_book("user004", "isbn4")  # 赵六借阅《isbn4》

        # 3. 还书操作
        return_book("user001", "isbn1")  # 张三归还《isbn1》

        # 4. 推荐系统
        print("\n=== 第一次推荐 ===")
        recommend_books("user001")

        # 5. 更多借阅
        borrow_book("user001", "isbn5")  # 张三借阅《isbn5》
        borrow_book("user002", "isbn6")  # 李四借阅《isbn6》

        # 6. 查看最终状态
        show_borrowing_status()

        # 7. 最终推荐
        print("\n=== 最终推荐 ===")
        recommend_books("user003")

    finally:
        # 关闭驱动连接
        driver.close()
        print("\n数据库连接已关闭")
